﻿using SuperX.Common.Collection;
using SuperX.Common.Log;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace SuperX.Common.MSG
{
    public class MsgCache : IMsgCache
    {
        public MsgCacheConfig MsgCacheConfig { get; } = new MsgCacheConfig();

        public event EventHandler<MsgEventArgs> MsgReceived;

        public MsgCache(IProject parent)
        {
            this._parent = parent;
        }

        public void Listen(IBasicObject baseObject)
        {
            if (baseObject == null)
            {
                return;
            }
            ITag tag = baseObject as ITag;
            if (tag != null)
            {
                
            }
            baseObject.PropertyChanged += new PropertyChangedEventHandler(this.BaseObject_PropertyChanged);
            baseObject.NotifyMessage += this.BaseObject_NotifyMessage;
            ICollectionNotify collectionNotify = baseObject as ICollectionNotify;
            if (collectionNotify != null)
            {
                collectionNotify.ItemAdded += this.ObjCollection_ItemAdded;
                collectionNotify.ItemCleared += this.ObjCollection_ItemCleared;
                collectionNotify.ItemRemoved += this.ObjCollection_ItemRemoved;
                collectionNotify.ItemReplaced += this.ObjCollection_ItemReplaced;
            }
        }

        // 
        private void AddMsg(Message msg)
        {
            if (this.MsgCacheConfig.OutputToLog)
            {
                Task.Factory.StartNew(delegate ()
                {
                    Logger.Trace(msg.JsonSerialize());
                });
            }
            EventHandler<MsgEventArgs> msgReceived = this.MsgReceived;
            if (msgReceived == null)
            {
                return;
            }
            msgReceived(this, new MsgEventArgs(msg));
        }

        private bool CanListen()
        {
            return this.MsgCacheConfig.EnableListen && this._enable && !this._threadTagManager.HaveTag();
        }

        public void UnListen(IBasicObject baseObject)
        {
            if (baseObject == null)
            {
                return;
            }
            baseObject.PropertyChanged -= new PropertyChangedEventHandler(this.BaseObject_PropertyChanged);
            baseObject.NotifyMessage -= this.BaseObject_NotifyMessage;
            ICollectionNotify collectionNotify = baseObject as ICollectionNotify;
            if (collectionNotify != null)
            {
                collectionNotify.ItemAdded -= this.ObjCollection_ItemAdded;
                collectionNotify.ItemCleared -= this.ObjCollection_ItemCleared;
                collectionNotify.ItemRemoved -= this.ObjCollection_ItemRemoved;
                collectionNotify.ItemReplaced -= this.ObjCollection_ItemReplaced;
            }
            ITag tag = baseObject as ITag;
            if (tag != null)
            {
                
            }
        }

        public void TagCurrentThread()
        {
            this._threadTagManager.Tag();
        }

        public void UnTagCurrentThread()
        {
            this._threadTagManager.UnTag();
        }

        public void Reset()
        {
            this._threadTagManager.Clear();
            this.EnableListen();
        }

        private void Tag_ValueChanged(object sender, TagChangedEventArgs e)
        {
            if (!this.CanListen())
            {
                return;
            }
            if (e.EventType != ValueChangedType.OnlyQualityChanged)
            {
                ValueMsg valueMsg = new ValueMsg();
                valueMsg.MsgSource = e.UpdateSourceName;
                ITag tag = e.Tag;
                valueMsg.FullName = ((tag != null) ? tag.FullName : null);
                valueMsg.TimeStamp = DateTime.Now;
                valueMsg.Value = e.Value;
                valueMsg.OldValue = e.OldValue;
                ITag tag2 = e.Tag;
                string valueType;
                if (tag2 == null)
                {
                    valueType = null;
                }
                else
                {
                    Type valueType2 = tag2.ValueType;
                    valueType = ((valueType2 != null) ? valueType2.FullName : null);
                }
                valueMsg.ValueType = valueType;
                ValueMsg msg = valueMsg;
                this.AddMsg(msg);
            }
        }

        // Token: 0x060003B1 RID: 945 RVA: 0x00006EFF File Offset: 0x000050FF
        private void BaseObject_NotifyMessage(object sender, MsgEventArgs e)
        {
            if (!this.CanListen())
            {
                return;
            }
            this.AddMsg(e.Msg);
        }

        private void ObjCollection_ItemReplaced(object sender, CollectionChangedArgs e)
        {
            if (!this.CanListen())
            {
                return;
            }
            IBasicObject baseObject = sender as IBasicObject;
            if (baseObject != null)
            {
                CollectionMsg msg = new CollectionMsg
                {
                    FullName = baseObject.FullName,
                    TimeStamp = DateTime.Now,
                    EventName = "Replace",
                    Item = e.Item
                };
                this.AddMsg(msg);
            }
        }

        private void ObjCollection_ItemRemoved(object sender, CollectionChangedArgs e)
        {
            if (!this.CanListen())
            {
                return;
            }
            IBasicObject baseObject = sender as IBasicObject;
            if (baseObject != null)
            {
                CollectionMsg msg = new CollectionMsg
                {
                    FullName = baseObject.FullName,
                    TimeStamp = DateTime.Now,
                    EventName = "Remove",
                    Item = e.Item
                };
                this.AddMsg(msg);
            }
        }

        private void ObjCollection_ItemCleared(object sender, CollectionChangedArgs e)
        {
            if (!this.CanListen())
            {
                return;
            }
            IBasicObject baseObject = sender as IBasicObject;
            if (baseObject != null)
            {
                CollectionMsg msg = new CollectionMsg
                {
                    FullName = baseObject.FullName,
                    TimeStamp = DateTime.Now,
                    EventName = "Clear",
                    Item = e.Item
                };
                this.AddMsg(msg);
            }
        }

        private void ObjCollection_ItemAdded(object sender, CollectionChangedArgs e)
        {
            if (!this.CanListen())
            {
                return;
            }
            IBasicObject baseObject = sender as IBasicObject;
            if (baseObject != null)
            {
                CollectionMsg msg = new CollectionMsg
                {
                    FullName = baseObject.FullName,
                    TimeStamp = DateTime.Now,
                    EventName = "Add",
                    Item = e.Item
                };
                this.AddMsg(msg);
            }
        }

        private void BaseObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Value" && sender is ITag)
            {
                return;
            }
            if (!this.CanListen())
            {
                return;
            }
            IBasicObject baseObject = sender as IBasicObject;
            if (baseObject != null)
            {
                PropertyMsg propertyMsg = new PropertyMsg
                {
                    FullName = baseObject.FullName,
                    TimeStamp = DateTime.Now,
                    PropertyName = e.PropertyName
                };
                propertyMsg.Value = baseObject.GetPropertyValue(e.PropertyName);
                PropertyMsg propertyMsg2 = propertyMsg;
                object value = propertyMsg.Value;
                propertyMsg2.ValueType = ((value != null) ? value.GetType().FullName : null);
                this.AddMsg(propertyMsg);
            }
        }

        public void UnEnableListen()
        {
            this._enable = false;
        }

        public void EnableListen()
        {
            this._enable = true;
        }

        private MsgCache.ThreadTagManager _threadTagManager = new MsgCache.ThreadTagManager();

        private object _lockObj = new object();

        private bool _enable;

        private readonly IProject _parent;

        public class ThreadTagManager
        {
            public void Clear()
            {
                this._threadFlagDic.Clear();
            }

            public void Tag()
            {
                this._threadFlagDic.TryAdd(Thread.CurrentThread.ManagedThreadId, null);
            }

            public void UnTag()
            {
                object obj;
                this._threadFlagDic.TryRemove(Thread.CurrentThread.ManagedThreadId, out obj);
            }

            public bool HaveTag()
            {
                return this._threadFlagDic.ContainsKey(Thread.CurrentThread.ManagedThreadId);
            }

            private ConcurrentDictionary<int, object> _threadFlagDic = new ConcurrentDictionary<int, object>();
        }
    }
}
